package com.geekstudy.week4.proxy;


import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Locale;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public class DynamicProxyInvocationContext {

    private Map<String, Object> contextMap;

    private Map<Class, InvocationHandler> handlerMap;

    private Map<String, Object> proxyMap;

    public DynamicProxyInvocationContext() {
        contextMap = new ConcurrentHashMap<String, Object>();
        handlerMap = new ConcurrentHashMap<Class, InvocationHandler>();
        proxyMap = new ConcurrentHashMap<String, Object>();
    }

    public <T> T addTarget(T target, Class c){
        String targetName = defaultTargetName(target);
        return addTarget(targetName, target, c);
    }

    public <T> T addTarget(String name, T target, Class c) {
        contextMap.put(name, target);
        InvocationHandler invocationHandler = new InvocationHandler()  {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                return method.invoke(target, args);
            }
        };
        handlerMap.put(target.getClass(), invocationHandler);
        Object proxy = Proxy.newProxyInstance(c.getClassLoader(), new Class<?>[]{c}, invocationHandler);
        T dynamic = (T)proxy;
        //if(proxy.getClass().equals(target.getClass())) {
        //    dynamic = (T) proxy;
        //}
        return dynamic;
    }

    public static <T> String defaultTargetName(T target) {
        String simpleName = target.getClass().getSimpleName();
        String targetName = simpleName.substring(0, 1).toLowerCase() + simpleName.substring(1, simpleName.length());
        return targetName;
    }

    public <T> T getTarget(Class t) {
        T target = null;
        for(Object existTarget :contextMap.values()) {
            if(existTarget.getClass().equals(t) || existTarget.getClass().getClass().equals(t)) {
                target = (T)existTarget;
            }
        }
        return target;
    }


}
